import java.rmi.* ; 
import java.rmi.server.UnicastRemoteObject ;
import java.net.MalformedURLException ; 
import java.util.Hashtable;
import java.util.*;

import java.rmi.RemoteException ;

public class Client_Impl extends UnicastRemoteObject implements Client_Itf 
{
	int id; //sert de capacite
	Hashtable listeVoisins = new Hashtable();
	int idPremierEmetteurJeton;
	Serveur_Itf s;
	String ip;

	public Client_Impl (String adServeur, String adip) throws RemoteException 
	{
		try 
		{
			s =(Serveur_Itf) Naming.lookup("rmi://"+ adServeur +"/Serveur");

			id = s.addList(this);
			System.out.println("je suis le client " + id);
			
			s.getVoisins(id);
			
			ip = adip;
		}
		catch (NotBoundException re) 
		{ 
			System.out.println(re); 
		}
		catch (RemoteException re) 
		{ 
			System.out.println(re); 
		}
		catch (MalformedURLException e) 
		{ 
			System.out.println(e); 
		}
	}

	public void addVoisinConnection(Client_Itf cNouveauVoisin, int idNouveauVoisin) throws RemoteException
	{
		try
		{	
			String cle = "" + idNouveauVoisin;
			listeVoisins.put(cle, cNouveauVoisin);
			System.out.println("Nouveau voisin : " + idNouveauVoisin);

			cNouveauVoisin.addVoisin(this, id);
		}
		catch (NullPointerException re) 
		{ 
			//System.out.println(re); 
		}
	}
	
	public void addVoisin(Client_Itf cNouveauConnecte, int idNouveauConnecte) throws RemoteException
	{
		String cle = "" + idNouveauConnecte;
		listeVoisins.put(cle, cNouveauConnecte);
		System.out.println("Nouveau voisin : " + idNouveauConnecte);
	}
	
	public void election(int idEmetteur, int capacite, int idCapacite, Hashtable liste, int idInit, int type) throws RemoteException
	{	
		if(liste.containsKey("" + id)) 					// si on est dans la liste, cela signifie que l'on a déjà reçu le jeton
		{
			
			int nextVoisin = trouverVoisin(liste);
			
			if(nextVoisin != -1) 						// si on a encore un voisin qui n'a pas recu le jeton
			{
				((Client_Itf) listeVoisins.get("" + nextVoisin)).election(id, capacite, idCapacite, liste, idInit, type);	// on lui envoie
			}
			else 										// s'il n'y en a pas, on renvoie à celui qui nous l'a envoyé
			{
				if(id == idInit) 						// si le jeton est au point de départ
				{
					if(type == 0)						// si election
					{
						this.election(id, id, idCapacite,new Hashtable(), id, 1);	// 1 : information -> informer le mec élu qu'il est élu
					}
				}
				else									// sinon on l'envoie au précédent
				{
					((Client_Itf) listeVoisins.get("" + idPremierEmetteurJeton)).election(id, capacite, idCapacite, liste, idInit, type);
				}
			}
			
			
		}
		else 													// sinon c'est la premiere fois qu'on reçoit le jeton
		{
			
			
			idPremierEmetteurJeton = idEmetteur;
			liste.put(""+id,this);								// on s'ajoute dans la liste
			
			if(type == 0)										// si election
			{
				capacite = capacite > id ? capacite : id; 		// capacite max
				idCapacite = capacite > id ? idCapacite : id;	// id de la capacite max
			}
			else												// sinon information
			{
				if(idCapacite == id)
				{
					System.out.println("J'ai été élu par " + idInit + " !");
					System.out.println("J'envois mon ip et mon n° de port au serveur");
					System.out.println("\tip : " + ip + " / port : " + 4242);
					s.iSend(ip,4242);
				}

				if(id == idInit)
				{
					System.out.println("J'ai élu "+ idCapacite +"!");
					System.out.println("Je récupère l'ip et le port du client élu sur le serveur");
					String session = s.iReceive() + "/60"; //<ip>/<port>/<ttl>
					System.out.println("\tsession : " + session);
					
				}
				if(idCapacite != id && id != idInit)
				{
					System.out.println("Je sais que " + idInit + " a élu "+ idCapacite +"!");
				}

			}
		
			int nextVoisin = trouverVoisin(liste);
			
			if(nextVoisin != -1) 								// si on a encore un voisin qui n'a pas recu le jeton
			{
				((Client_Itf) listeVoisins.get("" + nextVoisin)).election(id, capacite, idCapacite, liste, idInit, type);	// on lui envoie
			}
			else 												// s'il n'y en a pas, on renvoit à celui qui nous l'a envoyé
			{
				if(id == idInit)
				{
					this.election(id, capacite, idCapacite, liste, idInit, type);
				}
				else
				{
					((Client_Itf) listeVoisins.get("" + idPremierEmetteurJeton)).election(id, capacite, idCapacite, liste, idInit, type);
				}
			}
		}
	}
	
	public int trouverVoisin(Hashtable liste) throws RemoteException
	{
		boolean trouve = false;
		int retour=-1;
		
		for(Enumeration e = listeVoisins.keys(); e.hasMoreElements();)
		{
			String cle = (String)e.nextElement();
			
			if(!trouve)
			{
				if(!liste.containsKey(cle))
				{
					trouve = true;
					retour = Integer.parseInt(cle);
				}
			} 
		}
		return retour;
	}
}
